require'love.math'
require'socket'

local floor_tile = 0
local wall_tile = 1

function retrieve_chan(name)
    if not name then return nil end
    chan = love.thread.getChannel(name)
    if chan:peek() then
        return chan:pop()
    end
end

function push_chan(name, data)
    if not name or not data then return nil end
    chan = love.thread.getChannel(name)
    chan:push(data)
end

function push_tile(tile)
    push_chan('new_tile', tile)
end

function push_progress(msg)
    push_chan('closet_progress', msg)
end
    
function get_percent(lesser, greater)
	local n = lesser/greater
	n = math.floor(n*100)
	return n
end

function get_random_tile(line)
    local line = line or 45
    local r = love.math.random(100)
    if r < line then
        return wall_tile
    else
        return floor_tile
    end
   
end

function surrounding_tiles(map, tile, distX, distY, match)
    local matches = {}
    -- my best solve for surrounding tiles yet
    for y1 = -distY, distY do
        if map[tile.y+y1] then
            for x1 = 0, distX do
                if map[tile.y+y1][tile.x+x1] then
                    if y1 == 0 and x1 == 0 then
                        
                    elseif map[tile.y+y1][tile.x+x1].type == match then
                        matches[#matches+1] = map[tile.y+y1][tile.x+x1]
                    end
                end
            end
        end        
    end
    
    return matches      
        
end

function tiles_mod(map, tile, x_mod, y_mod, match)    
    if map[tile.y+y_mod][tile.x+x_mod].type == match then
        return true
    end
    return false
end

function up_tiles(map, tile, match)
    local a, b, c
    
    if tiles_mod(map,tile,0,-1,match) then
        a = true
    end
    
    if tiles_mod(map,tile,1,0,match) then
        b = true
    end
    
    if tiles_mod(map, tile,-1,0, match) then
        c = true
    end
    
    if a == true and b == true and c == true then
        return true
    end
    return false
end

function down_tiles(map, tile, match)
    local a, b, c
    
    if tiles_mod(map,tile,0,1,match) then
        a = true
    end
    
    if tiles_mod(map,tile,1,0,match) then
        b = true
    end
    
    if tiles_mod(map, tile,-1,0, match) then
        c = true
    end
    
    if a == true and b == true and c == true then
        return true
    end
    return false
end

function right_tiles(map, tile, match)
    local a, b, c
    
    if tiles_mod(map,tile,0,1,match) then
        a = true
    end
    
    if tiles_mod(map,tile,1,0,match) then
        b = true
    end
    
    if tiles_mod(map, tile,0,-1, match) then
        c = true
    end
    
    if a == true and b == true and c == true then
        return true
    end
    return false
end

function left_tiles(map, tile, match)
    local a, b, c
    
    if tiles_mod(map,tile,0,1,match) then
        a = true
    end
    
    if tiles_mod(map,tile,-1,0,match) then
        b = true
    end
    
    if tiles_mod(map, tile,0,-1, match) then
        c = true
    end
    
    if a == true and b == true and c == true then
        return true
    end
    return false
end


local stats = retrieve_chan('closet_stats')
local seed = retrieve_chan('closet_seed')
local reps = retrieve_chan('closet_reps')
local reps2 = retrieve_chan('closet_reps2')
local current_floor = retrieve_chan('closet_floor')

--if not seed then seed = socket.gettime()*1000*os.time() end
if not reps then reps = 5 end
if not reps2 then reps2 = 5 end
if not current_floor then current_floor = 1 end

--love.math.setRandomSeed(seed)

local tiles_x = stats.lat
local tiles_y = stats.long
local floors = stats.ele


local floor_map = {}
-- initial map
for y = 1, tiles_y do
    floor_map[y] = {}
    for x = 1, tiles_x do
        floor_map[y][x] = {}
        local tile = {}
        tile.x = x
        tile.y = y
        tile.z = current_floor
        if y == 1 or x == 1 or x == tiles_x or y == tiles_y then
            tile.type = wall_tile
        else
            tile.type = get_random_tile()
        end       
        floor_map[y][x] = tile
        local pz = get_percent(y, tiles_y)
        push_progress("Initial Generation " .. pz .. "% complete")
    end
end

for i = 1, reps do
    for y = 1, tiles_y do
        if y ~= 1 and y ~= tiles_y then
            for x = 1, tiles_x do
                if x ~=1 and x ~= tiles_x then    
                    local tile = floor_map[y][x]
                    local nearby_tiles = surrounding_tiles(floor_map, tile, 1, 1, wall_tile)
                    
                    if #nearby_tiles > 5 then
                        floor_map[y][x].type = wall_tile
                    end
                    
                    if #nearby_tiles < 2 then
                        --if i % reps == 0 or i == reps then
                            floor_map[y][x].type = wall_tile
                        --end        
                    end
                    
                    
                        
                end
            end
        end
    end
    local pz = get_percent(i, reps)
    push_progress("Refining " .. pz .. "% complete")
end

for i = 1, reps2 do
    for y = 1, tiles_y do
        if y ~= 1 and y ~= tiles_y then
            for x = 1, tiles_x do
                if x ~=1 and x ~= tiles_x then    
                    local tile = floor_map[y][x]
                    local nearby_tiles = surrounding_tiles(floor_map, tile, 1, 1, floor_tile)                    
                    
                    if up_tiles(floor_map, tile, floor_tile) then
                        floor_map[y][x].type = floor_tile
                    elseif down_tiles(floor_map, tile, floor_tile) then
                        floor_map[y][x].type = floor_tile
                    end
                    
                    if i == reps2 then
                        if right_tiles(floor_map, tile, floor_tile) then
                            floor_map[y][x].type = floor_tile
                        end
                    end
                    
                    if i == 1 then
                        if left_tiles(floor_map, tile, floor_tile) then
                            floor_map[y][x].type = floor_tile
                        end
                    end                  
                    
                        
                end
            end
        end
    end
    local pz = get_percent(i, reps2)
    push_progress("Refining " .. pz .. "% complete")
end  

local sent_tiles = false
local delay = 10000
local dt = 0
local iter_y = 1
local iter_x = 1
while sent_tiles == false do
    dt = dt + 1
    if dt > delay then
        dt = 0
        push_tile(floor_map[iter_y][iter_x])
        iter_x = iter_x + 1
        if iter_x > tiles_x then
            iter_x = 1
            iter_y = iter_y + 1
        end
        
        local pz = get_percent(iter_y, tiles_y)
        push_progress("Sending Queue " .. pz .. "% complete")
        
        if iter_y > tiles_y then
            sent_tiles = true
        end
        
        
    end
      
end

push_progress('complete')
